/**
 * Copyright (c) 2012-2014, Yang Yang <cntototo@gmail.com>
 *
 * This software may be distributed under the terms of the New BSD License.
 * See README for more details.
 */

#ifndef DRIVER_H
#define DRIVER_H

#include <stddef.h>

#include "os.h"
#include "def.h"
#include "if_manager.h"

enum wfs_driver_hidden_ssid_flag {
	WFS_DRV_HIDDEN_SSID_NOT_IN_USE,
	WFS_DRV_HIDDEN_SSID_ZERO_LEN,
	WFS_DRV_HIDDEN_SSID_ZERO_CONTENTS
};

enum wfs_driver_hw_mode {
	WFS_DRV_HW_MODE_UNKNOWN		= 0x0000,
	WFS_DRV_HW_MODE_IEEE80211B	= 0x0001,
	WFS_DRV_HW_MODE_IEEE80211G	= 0x0002,
	WFS_DRV_HW_MODE_IEEE80211A	= 0x0004,
	WFS_DRV_HW_MODE_IEEE80211AD	= 0x0008,
};

/**
 * struct wfs_driver_capa -- Driver capability info
 */
struct wfs_driver_capa {
	/** Is capa structure filled or not */
	u8 filled;
#define DRIVER_CAPA_KEY_MGMT_WPA	0x00000001
#define DRIVER_CAPA_KEY_MGMT_WPA2	0x00000002
#define DRIVER_CAPA_KEY_MGMT_WPA_PSK	0x00000004
#define DRIVER_CAPA_KEY_MGMT_WPA2_PSK	0x00000008
#define DRIVER_CAPA_KEY_MGMT_WPA_NONE	0x00000010
#define DRIVER_CAPA_KEY_MGMT_FT		0x00000020
#define DRIVER_CAPA_KEY_MGMT_FT_PSK	0x00000040
#define DRIVER_CAPA_KEY_MGMT_WAPI_PSK	0x00000080
	u32 key_mgmt;

#define DRIVER_CAPA_ENC_WEP40		0x00000001
#define DRIVER_CAPA_ENC_WEP104		0x00000002
#define DRIVER_CAPA_ENC_TKIP		0x00000004
#define DRIVER_CAPA_ENC_CCMP		0x00000008
#define DRIVER_CAPA_ENC_WEP128		0x00000010
#define DRIVER_CAPA_ENC_GCMP		0x00000020
#define DRIVER_CAPA_ENC_GCMP_256	0x00000040
#define DRIVER_CAPA_ENC_CCMP_256	0x00000080
#define DRIVER_CAPA_ENC_BIP		0x00000100
#define DRIVER_CAPA_ENC_BIP_GMAC_128	0x00000200
#define DRIVER_CAPA_ENC_BIP_GMAC_256	0x00000400
#define DRIVER_CAPA_ENC_BIP_CMAC_256	0x00000800
	u32 enc;

#define DRIVER_CAPA_AUTH_OPEN		0x00000001
#define DRIVER_CAPA_AUTH_SHARED		0x00000002
#define DRIVER_CAPA_AUTH_LEAP		0x00000004
	u32 auth;

/** Driver generated WPA/RSN IE */
#define DRIVER_CAPA_FLAGS_DRIVER_IE			0x00000001
/** Driver needs static WEP key setup after association command */
#define DRIVER_CAPA_FLAGS_SET_KEYS_AFTER_ASSOC		0x00000002
/** unused: 0x00000004 */
/**
 * Driver takes care of RSN 4-way handshake internally; PMK is configured with
 * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK
 */
#define DRIVER_CAPA_FLAGS_4WAY_HANDSHAKE		0x00000008
#define DRIVER_CAPA_FLAGS_WIRED				0x00000010
/** Driver provides separate commands for authentication and association */
#define DRIVER_CAPA_FLAGS_SME				0x00000020
/** Driver supports AP mode */
#define DRIVER_CAPA_FLAGS_AP				0x00000040
/** Driver needs static WEP key setup after association has been completed */
#define DRIVER_CAPA_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
/** unused: 0x00000100 */
/** Driver supports concurrent P2P operations */
#define DRIVER_CAPA_FLAGS_P2P_CONCURRENT		0x00000200
/**
 * Driver uses the initial interface as a dedicated management interface, i.e.,
 * it cannot be used for P2P group operations or non-P2P purposes.
 */
#define DRIVER_CAPA_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
/** This interface is P2P capable (P2P GO or P2P Client) */
#define DRIVER_CAPA_FLAGS_P2P_CAPABLE			0x00000800
/** unused: 0x00001000 */
/**
 * Driver uses the initial interface for P2P management interface and non-P2P
 * purposes (e.g., connect to infra AP), but this interface cannot be used for
 * P2P group operations.
 */
#define DRIVER_CAPA_FLAGS_P2P_MGMT_AND_NON_P2P		0x00002000
/**
 * Driver is known to use sane error codes, i.e., when it indicates that
 * something (e.g., association) fails, there was indeed a failure and the
 * operation does not end up getting completed successfully later.
 */
#define DRIVER_CAPA_FLAGS_SANE_ERROR_CODES		0x00004000
/** Driver supports off-channel TX */
#define DRIVER_CAPA_FLAGS_OFFCHANNEL_TX			0x00008000
/** Driver indicates TX status events for EAPOL Data frames */
#define DRIVER_CAPA_FLAGS_EAPOL_TX_STATUS		0x00010000
/** Driver indicates TX status events for Deauth/Disassoc frames */
#define DRIVER_CAPA_FLAGS_DEAUTH_TX_STATUS		0x00020000
/** Driver supports roaming (BSS selection) in firmware */
#define DRIVER_CAPA_FLAGS_BSS_SELECTION			0x00040000
/** Driver supports operating as a TDLS peer */
#define DRIVER_CAPA_FLAGS_TDLS_SUPPORT			0x00080000
/** Driver requires external TDLS setup/teardown/discovery */
#define DRIVER_CAPA_FLAGS_TDLS_EXTERNAL_SETUP		0x00100000
/** Driver indicates support for Probe Response offloading in AP mode */
#define DRIVER_CAPA_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
/** Driver supports U-APSD in AP mode */
#define DRIVER_CAPA_FLAGS_AP_UAPSD			0x00400000
/** Driver supports inactivity timer in AP mode */
#define DRIVER_CAPA_FLAGS_INACTIVITY_TIMER		0x00800000
/** Driver expects user space implementation of MLME in AP mode */
#define DRIVER_CAPA_FLAGS_AP_MLME			0x01000000
/** Driver supports SAE with user space SME */
#define DRIVER_CAPA_FLAGS_SAE				0x02000000
/** Driver makes use of OBSS scan mechanism */
#define DRIVER_CAPA_FLAGS_OBSS_SCAN			0x04000000
/** Driver supports IBSS (Ad-hoc) mode */
#define DRIVER_CAPA_FLAGS_IBSS				0x08000000
/** Driver supports radar detection */
#define DRIVER_CAPA_FLAGS_RADAR				0x10000000
/** Driver supports a dedicated interface for P2P Device */
#define DRIVER_CAPA_FLAGS_DEDICATED_P2P_DEVICE		0x20000000
/** Driver supports QoS Mapping */
#define DRIVER_CAPA_FLAGS_QOS_MAPPING			0x40000000
/** Driver supports CSA in AP mode */
#define DRIVER_CAPA_FLAGS_AP_CSA			0x80000000
	u32 flags;

	u32 max_scan_ssids;
	u32 max_sched_scan_ssids;
	u32 max_match_sets;

/** Default maximum remain-on-channel duration in msec */
#define DRIVER_CAPA_DEFAULT_MAX_ROC_DURATION	5000
	/** Maximum remain-on-channel duration in msec */
	u32 max_roc_dur;
	/**
	 * Maximum number of associated stations the driver supports
	 * in AP mode
	 */
	u32 max_stations;
	/**
	 * Bitmap of supported protocols by the driver for Probe response
	 * offloading
	 */
/** Driver Probe Response offloading support for WPS ver. 1 */
#define DRIVER_CAPA_PROBE_RESP_OFFLOAD_WPS		0x00000001
/** Driver Probe Response offloading support for WPS ver. 2 */
#define DRIVER_CAPA_PROBE_RESP_OFFLOAD_WPS2		0x00000002
/** Driver Probe Response offloading support for P2P */
#define DRIVER_CAPA_PROBE_RESP_OFFLOAD_P2P		0x00000004
/** Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
#define DRIVER_CAPA_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
	u32 probe_resp_offloads;
	u32 max_acl_mac_addrs;
	/** Number of supported concurrent channels */
	u32 num_concur_chans;
	/**
	 * Extended capabilities in driver
	 * Must be allocated and freed by driver and the pointers must be
	 * valid for the lifetime of the driver, i.e., freed in deinit()
	 */
	u8 *ext_capa;
	u8 *ext_capa_mask;
	u32 ext_capa_len;
	/** Has AP SME support */
	u8 device_ap_sme;
	/** Has probe client support */
	u8 probe_client;
	/** Has monitor support */
	u8 monitor;
	/** Has connect support */
	u8 connect;
	/** Has scheduled scan support */
	u8 sched_scan;
	/** Has socket TX status support */
	u8 sk_tx_status;
};

enum wfs_driver_chan_flag {
	WFS_DRV_CHAN_DISABLED		= 0x00000001,
	WFS_DRV_CHAN_PASSIVE_SCAN	= 0x00000002,
	WFS_DRV_CHAN_NO_IBSS		= 0x00000004,
	WFS_DRV_CHAN_RADAR		= 0x00000008,
	WFS_DRV_CHAN_HT40PLUS		= 0x00000010,
	WFS_DRV_CHAN_HT40MINUS		= 0x00000020,
	WFS_DRV_CHAN_HT40		= 0x00000040,
	/** Reserve 0x00000080 */
	WFS_DRV_CHAN_DFS_UNKNOWN	= 0x00000000,
	WFS_DRV_CHAN_DFS_USABLE		= 0x00000100,
	WFS_DRV_CHAN_DFS_UNAVAILABLE	= 0x00000200,
	WFS_DRV_CHAN_DFS_AVAILABLE	= 0x00000300,
	WFS_DRV_CHAN_DFS_MASK		= 0x00000300,
	/** Reserve */
	WFS_DRV_CHAN_VHT_10_70		= 0x00001000,
	WFS_DRV_CHAN_VHT_30_50		= 0x00002000,
	WFS_DRV_CHAN_VHT_50_30		= 0x00004000,
	WFS_DRV_CHAN_VHT_70_10		= 0x00008000,
};

struct wfs_driver_chan_info {
	/** Channel number (IEEE 802.11) */
	u16 chan;
	/** Frequency in MHz */
	u32 freq;
	/** Channel flags */
	enum wfs_driver_chan_flag flags;
	/** Regulatory transmit power limit in dBm */
	u8 max_tx_power;
	/** Minimum observed noise floor */
	s8 min_nf;
};

/**
 * struct wfs_hw_info
 */
struct wfs_driver_hw_info {
	/** Hardware mode */
	enum wfs_driver_hw_mode mode;
	/** Supported channels */
	struct wfs_driver_chan_info *channels;
	/** Number of channels */
	u32 channels_num;
	/** Supported rates in 100 Kbps */
	u32 *rates;
	/** Number of rates */
	u32 rates_num;
	/** HT (IEEE 802.11n) capabilities */
	u16 ht_caps;
	/** HT MCS rates */
	u8 ht_mcs_set[16];
	/** AMPDU (IEEE 802.11n) */
	u8 ampdu_params;
	/** VHT (IEEE 802.11ac) capabilities */
	u32 vht_caps;
	/** VHT MCS rates */
	u8 vht_mcs_set[8];
};

/**
 * struct wfs_driver_ap_params -- AP parameters
 */
struct wfs_driver_ap_params {
	/** Beacon head */
	u8 *head;
	/** Length of beacon head */
	u32 head_len;
	/** Beacon tail */
	u8 *tail;
	/** Length of beacon tail */
	u32 tail_len;
	/** Beacon interval */
	u32 interval;
	/** DTIM period */
	u32 dtim_period;
	/** Basic rates in 100 Kbps */
	u32 *basic_rates;
	/** Length of basic rates */
	u32 basic_rates_len;
	/** SSID */
	u8 *ssid;
	/** Length of SSID */
	u32 ssid_len;
	/** Probe response */
	u8 *probe_resp;
	/** Length of probe response */
	u32 probe_resp_len;
	/** Flag of hidden SSID */
	enum wfs_driver_hidden_ssid_flag hidden_ssid;
	/** Is privacy used or not */
	u8 is_privacy;
	/** Authentication algorithm */
	enum wfs_auth_alg auth_alg;
	/** WPA version */
	u32 wpa_version;
	/** Key management suites */
	u32 key_mgmt_suites;
	/** Pairwise ciphers */
	enum wfs_cipher pairwise_ciphers;
	/** Group cipher */
	enum wfs_cipher group_cipher;
	/** Beacon IE -- P2P/WPS IE(s) for Beacon frame */
	u8 *beacon_ie;
	/** Length of Beacon IE */
	u32 beacon_ie_len;
	/** Probe resp IE -- P2P/WPS IE(s) for Probe response frame */
	u8 *probe_resp_ie;
	/** Length of Probe response IE */
	u32 probe_resp_ie_len;
	/** Assoc resp IE -- P2P/WPS IE(s) for Association response frame */
	u8 *assoc_resp_ie;
	/** Length of Assoc resp IE */
	u32 assoc_resp_ie_len;
	/** Whether to isolate frames between associated stations */
	int need_isolation;
	/** Whether CTS protection is enabled */
	int cts_protection_enabled;
	/** Whether short preamble is enabled */
	int preamble_enabled;
	/** Whether short slot time is enabled */
	int sst_enabled;
	/** HT operation mode */
	int ht_opmode;
	/** Whether interworking is enabled */
	int interworking_enabled;
	/** Homogeneous ESSID */
	const u8 *homo_essid;
	/** Access network type */
	u8 access_network_type;
	/** Timeout in seconds to detect STA's inactivity */
	int ap_max_inactivity;
	/** Whether group-addressed frames are enabled */
	int gaf_enabled;
	/** Related interface */
	struct wfs_iface *iface;
};

/**
 * struct wfs_driver_assoc_params -- Association parameters
 */
struct wfs_driver_assoc_params {
	/** BSSID of the selected AP */
	u8 bssid[ETH_ALEN];
	/** The selected SSID */
	u8 ssid[MAX_SSID_LEN];
	/** Length of the SSID */
	u32 ssid_len;
	/** Frequency of the channel the selected AP is using, in MHz */
	int freq;
	/** Passphrase */
	u8 passphrase[MAX_PASSPHRASE_LEN];
	/** Length of passphrase */
	u8 passphrase_len;
	/** PSK */
	u8 psk[PSK_BYTE_LEN];
	/** Background scan period in seconds */
	int bg_scan_period;
	/** IE */
	u8 *ie;
	/** Length of IE in bytes */
	u32 ie_len;
	/** Security protocol to indicate WPA/RSN/WAPI */
	enum wfs_security_protocol sec_proto;
	/** Allowed authentication algorithms */
	enum wfs_auth_alg auth_alg;
	/** Selected pairwise cipher suite */
	enum wfs_cipher pairwise_suite;
	/** Selected group cipher suite */
	enum wfs_cipher group_suite;
	/** Selected key management suite */
	enum wfs_key_mgmt key_mgmt_suite;
	/** IEEE 802.11w management frame protection option */
	enum wfs_mfp_options mfp_op;
	/** IEEE 802.11r FT information elements */
	u8 *ft_ie;
	/** Length of ft_ie in bytes */
	u32 ft_ie_len;
	/** Disable HT (IEEE 802.11n) for this connection */
	int disable_ht;
	/** HT Capabilities over-rides */
	struct ieee80211_ht_capabilities *ht_caps;
	/** Only bits set in the mask will be used */
	struct ieee80211_ht_capabilities *ht_caps_mask;
	/** Disable VHT (IEEE 802.11ac) for this connection */
	int disable_vht;
	/** VHT Capabilities over-rides */
	struct ieee80211_vht_capabilities *vht_caps;
	/** Only bits set in the mask will be used */
	struct ieee80211_vht_capabilities *vht_caps_mask;
	/** Previous BSSID */
	u8 prev_bssid[ETH_ALEN];
	/** Related interface */
	struct wfs_iface *iface;
};

/**
 * struct wfs_driver_auth_params -- Authentication parameters
 */
struct wfs_driver_auth_params {
	/** BSSID of the selected AP */
	u8 bssid[ETH_ALEN];
	/** The selected SSID */
	u8 *ssid;
	/** Length of the SSID */
	u32 ssid_len;
	/** Frequency of the channel the selected AP is using, in MHz */
	int freq;
	/** IE */
	const u8 *ie;
	/** Length of IE in bytes */
	u32 ie_len;
	/** Authentication algorithm */
	enum wfs_auth_alg auth_alg;
	/** WEP keys for static WEP configuration */
	const u8 *wep_key[4];
	/** WEP key length for static WEP configuration */
	u32 wep_key_len[4];
	/** WEP TX key index for static WEP configuration */
	int wep_tx_keyidx;
	/** Local state change */
	int local_state_change;
	/** Simultaneous authentication of equals data */
	const u8 *sae_data;
	/** Length of SAE data */
	u32 sae_data_len;
	/** Related interface */
	struct wfs_iface *iface;
};

/**
 * struct wfs_driver_cqm_params -- Connection quality monitor parameters
 */
struct wfs_driver_cqm_params {
	/** RSSI threshold in dBm to send event */
	s32 threshold;
	/** RSSI hysteresis in dBm. Minimum amount of change to send event */
	u32 hysteresis;
	/** Related interface */
	struct wfs_iface *iface;
};

enum wfs_driver_frame_type {
	/** Other frame */
	WFS_DRV_FT_DEFAULT,
	/** Action frame */
	WFS_DRV_FT_ACTION,
	/** MLME frame */
	WFS_DRV_FT_MLME
};

/**
 * struct wfs_driver_frame_params -- Management frame parameters
 */
struct wfs_driver_frame_params {
	/** Frame type */
	enum wfs_driver_frame_type frame_type;
	/** Is IEEE80211 header needed */
	u8 is_header_needed;
	/** Source address. Used when is_header_needed is true */
	const u8 *src;
	/** Destination address. Used when is_header_needed is true */
	const u8 *dst;
	/** BSSID. Used when is_header_needed is true */
	const u8 *bssid;
	/** Frame data */
	const u8 *data;
	/** Length of frame data */
	u32 data_len;
	/** Frequency of the channel in MHz */
	u32 freq;
	/** Is frame data encrypted */
	u8 is_encrypted;
	/** Don't wait for ack */
	u8 no_wait_ack;
	/** No CCK rate */
	u8 no_cck;
	/** Is off channel TX ok */
	u8 offchan_ok;
	/** Duration in msecs */
	u32 duration;
	/** Related interface */
	struct wfs_iface *iface;
};

enum wfs_driver_if_type {
	/** IBSS interface */
	WFS_DRV_IF_TYPE_ADHOC,
	/** Station mode interface */
	WFS_DRV_IF_TYPE_STATION,
	/**
	 * AP mode VLAN interface
	 * This interface shares its address and Beacon frame with the main BSS
	 */
	WFS_DRV_IF_TYPE_AP_VLAN,
	/**
	 * AP mode BSS interface
	 * This interface has its own address and Beacon frame
	 */
	WFS_DRV_IF_TYPE_AP_BSS,
	/** P2P client */
	WFS_DRV_IF_TYPE_P2P_CLIENT,
	/** P2P group owner */
	WFS_DRV_IF_TYPE_P2P_GO,
	/**
	 * P2P group interface
	 * This interface will become either GO or Client, but still
	 * not yet known
	 */
	WFS_DRV_IF_TYPE_P2P_GROUP,
	/** P2P device interface
	 * This interface is used to identify the abstracted P2P device
	 * function in the driver
	 */
	WFS_DRV_IF_TYPE_P2P_DEVICE
};

/**
 * struct wfs_driver_if_params -- Virtual interface parameters
 */
struct wfs_driver_if_params {
	/** Interface type */
	enum wfs_driver_if_type type;
	/** Related interface */
	struct wfs_iface *iface;
};

/**
 * struct wfs_driver_key_params -- Encryption key parameters
 */
struct wfs_driver_key_params {
	/** Cipher type */
	enum wfs_cipher cipher;
	/** Peer address */
	u8 peer_addr[ETH_ALEN];
	/** Key */
	const u8 *key;
	/** Length of key */
	u32 key_len;
	/** Key index */
	u8 key_idx;
	/** Key sequence number */
	const u8 *seq;
	/** Length of key sequence number */
	u32 seq_len;
	/** Is set the default TX key needed */
	int set_tx;
	/** Related interface */
	struct wfs_iface *iface;
};

/**
 * struct wfs_driver_scan_params -- Scan parameters
 */
struct wfs_driver_scan_params {
	/** Devices to scan for */
	struct scan_device {
		/** SSID to scan. NULL or zero-length means wildcard SSID */
		const u8 *ssid;
		/** Length of SSID in bytes */
		u32 ssid_len;
	} devices[MAX_SCAN_DEVICES];
	/** Number of devices to scan for */
	u16 device_num;
	/** Match Devices to scan */
	struct match_device {
		const u8 ssid[MAX_SSID_LEN];
		u32 ssid_len;
	} *match_devs;
	/** Number of match devices to scan */
	u32 match_devs_num;
	/** Threshold of RSSI in dBm */
	s32 rssi;
	/** Array of frequencies to scan */
	u32 *freqs;
	/** Number of frequencies to scan */
	u32 freq_num;
	/** Interval between scheduled scan cycles, in msecs */
	u32 interval;
	/** IE */
	u8 *ie;
	/** Length of IE in bytes */
	u32 ie_len;
	/** If P2P scan, CCK (802.11b) rates must be diabled */
	u8 is_p2p_scan;
	/** Ask driver to report only new scan results */
	u8 only_new_results;
	/** Related interface */
	struct wfs_iface *iface;
};

#define WFS_SCAN_QUAL_INVALID		BIT(0)
#define WFS_SCAN_NOISE_INVALID		BIT(1)
#define WFS_SCAN_LEVEL_INVALID		BIT(2)
#define WFS_SCAN_LEVEL_DBM		BIT(3)
#define WFS_SCAN_AUTHENTICATED		BIT(4)
#define WFS_SCAN_ASSOCIATED		BIT(5)

/**
 * struct wfs_idrver_scan_result -- Scan result for a BSS/IBSS
 */
struct wfs_driver_scan_result {
	/** Should this result kept */
	u8 keep;
	/** Information flags for the BSS/IBSS */
	u32 flags;
	/** BSSID */
	u8 bssid[ETH_ALEN];
	/** SSID */
	u8 ssid[MAX_SSID_LEN];
	/** Length of SSID */
	u32 ssid_len;
	/** Frequency of the channel in MHz */
	u32 freq;
	/** Beacon interval in TUs */
	u16 beacon_interval;
	/** Capability information field */
	u16 caps;
	/** Signal quality */
	u32 signal_qual;
	/** Noise level */
	u32 noise_level;
	/** Signal level */
	u32 signal_level;
	/** Timestamp */
	u64 tsf;
	/** How many msecs ago the last Beacon/Probe-response was received */
	u32 ago;
	/** IE */
	u8 *ie;
	/** Length of IE in bytes */
	u32 ie_len;
	/** Beacon IE */
	u8 *beacon_ie;
	/** Length of beacon IE in bytes */
	u32 beacon_ie_len;
};

struct wfs_driver_scan_results {
	/** Array of pointers to wfs_driver_scan_result */
	struct wfs_driver_scan_result **table;
	/** Number of entries in table */
	u32 num;
	/** Time when the results were fetched from the driver */
	struct wfs_timeval *fetch_time;
};

enum wfs_driver_sta_flags {
	/** Station is authorized (802.1X) */
	WFS_DRV_STA_AUTHORIZED		= 0x0001,
	/** Station is capable of receiving frames with short barker preamble */
	WFS_DRV_STA_SHORT_PREAMBLE	= 0x0002,
	/** Station is WME/QoS capable */
	WFS_DRV_STA_WME			= 0x0004,
	/** Station uses management frame protection */
	WFS_DRV_STA_MFP			= 0x0008,
	/** Station is authenticated */
	WFS_DRV_STA_AUTHENTICATED	= 0x0010,
	/** Station is a TDLS peer */
	WFS_DRV_STA_TDLS_PEER		= 0x0020,
	/** Station is associated */
	WFS_DRV_STA_ASSOCIATED		= 0x0040
};

struct wfs_driver_sta_add_params {
	/** Is new STA */
	u8 is_new;
	/** MAC address */
	u8 addr[ETH_ALEN];
	/** STA flags */
	enum wfs_driver_sta_flags sta_flags;
	/** AID */
	u16 aid;
	/** Supported rates in MHz */
	const u8 *supp_rates;
	/** Length of supported rates */
	u32 supp_rates_len;
	/** Listen interval */
	u16 listen_interval;
	/** HT (IEEE 802.11n) capabilities */
	const struct ieee80211_ht_capabilities *ht_caps;
	/** VHT (IEEE 802.11ac) capabilities */
	const struct ieee80211_vht_capabilities *vht_caps;
	/** STA capabilities */
	u16 sta_caps;
	/** Extended capabilities */
	const u8 *ext_caps;
	/** Length of extended capabilities */
	u32 ext_caps_len;
	/** QoS info */
	u8 qos_info;
	/** Related interface */
	struct wfs_iface *iface;
};

struct wfs_driver_ops {
	/** Driver name */
	const char *name;
	/** Driver description */
	const char *desc;
	/**
	 * associate -- Request driver to associate
	 * @params: association parameters
	 */
	enum wfs_internal_err
		(*associate)(struct wfs_driver_assoc_params *params);
	/**
	 * auth -- Request driver to authenticate
	 * @params: authentication parameters
	 */
	enum wfs_internal_err
		(*auth)(struct wfs_driver_auth_params *params);
	/**
	 * cancel_remain_on_channel -- Cancel remain-on-channel operation
	 * @cur_if: current interface
	 */
	enum wfs_internal_err
		(*cancel_remain_on_channel)(struct wfs_iface *cur_if);
	/**
	 * deauth -- Request driver to deauthenticate
	 * @cur_if: current interface
	 * @addr: peer address
	 * @reason_code: reason code in deauthentication frame
	 */
	enum wfs_internal_err
		(*deauth)(struct wfs_iface *cur_if, const u8 *addr,
				u16 reason_code);
	/**
	 * deinit -- Deinitialize driver information
	 * @cur_if: current interface
	 */
	enum wfs_internal_err
		(*deinit)(struct wfs_iface *cur_if);
	/**
	 * del_sta -- Delete a station entry (AP only)
	 * @cur_if: current interface
	 * @addr: station address to be deauthenticated
	 */
	enum wfs_internal_err
		(*del_sta)(struct wfs_iface *cur_if, const u8 *addr);
	/**
	 * get_bssid -- Get the current BSSID
	 * @cur_if: current interface
	 * @bssid: buffer for BSSID
	 */
	enum wfs_internal_err
		(*get_bssid)(struct wfs_iface *cur_if, u8 *bssid);
	/**
	 * get_country -- Get the regulatory domain
	 * @cur_if: current interface
	 * @country_code: returned country code (at least 3 bytes)
	 */
	enum wfs_internal_err
		(*get_country)(struct wfs_iface *cur_if, u8 *country_code);
	/**
	 * get_hw_info -- Get hardware information
	 * @cur_if: current interface
	 * @country_code: returned country code (at least 3 bytes)
	 */
	enum wfs_internal_err
		(*get_hw_info)(struct wfs_iface *cur_if);
	/**
	 * get_mac_addr -- Get MAC address
	 * @cur_if: current interface
	 * @addr: returned MAC address
	 */
	enum wfs_internal_err
		(*get_mac_addr)(struct wfs_iface *cur_if, u8 *addr);
	/**
	 * get_scan_results -- Get the latest scan results
	 * @cur_if: current interface
	 */
	struct wfs_driver_scan_results *
		(*get_scan_results)(struct wfs_iface *cur_if);
	/**
	 * get_ssid -- Get the current SSID
	 * @cur_if: current interface
	 * @ssid: buffer for SSID
	 * @ssid_len: length of SSID
	 */
	enum wfs_internal_err
		(*get_ssid)(struct wfs_iface *cur_if, u8 *ssid, u32 *ssid_len);
	/**
	 * if_add -- Add virtual interface
	 * @params: interface params
	 */
	enum wfs_internal_err
		(*if_add)(struct wfs_driver_if_params *params);
	/**
	 * if_remove -- Remove virtual interface
	 * @cur_if: current interface
	 */
	enum wfs_internal_err
		(*if_remove)(struct wfs_iface *cur_if);
	/**
	 * init -- Initialize driver information
	 * @cur_if: current interface
	 */
	enum wfs_internal_err
		(*init)(struct wfs_iface *cur_if);
	/**
	 * is_scan_ongoing -- Whether scan is ongoing
	 * @cur_if: current interface
	 */
	int
		(*is_scan_ongoing)(struct wfs_iface *cur_if);
	/**
	 * probe_client -- Probe an associated station on an AP interface
	 * @cur_if: current interface
	 * @addr: station address
	 * @is_qos: is QoS station or not
	 */
	enum wfs_internal_err
		(*probe_client)(struct wfs_iface *cur_if, const u8 *addr,
				u8 is_qos);
	/**
	 * remain_on_channel -- Remain awake on a channel
	 * @cur_if: current interface
	 * @freq: frequency of the channel in MHz
	 * @duration: duration in msecs
	 */
	enum wfs_internal_err
		(*remain_on_channel)(struct wfs_iface *cur_if, u32 freq,
				u32 duration);
	/**
	 * scan -- Request driver to initiate scan
	 * @params: scan parameters
	 */
	enum wfs_internal_err
		(*scan)(struct wfs_driver_scan_params *params);
	/**
	 * sched_scan -- Request driver to initiate scheduled scan
	 * @params: scan parameters
	 */
	enum wfs_internal_err
		(*sched_scan)(struct wfs_driver_scan_params *params);
	/**
	 * send_frame -- Send management frame
	 * @params: frame parameters
	 */
	enum wfs_internal_err
		(*send_frame)(struct wfs_driver_frame_params *params);
	/**
	 * send_frame_wait_cancel -- Cancel frame TX wait
	 * @cur_if: current interface
	 */
	enum wfs_internal_err
		(*send_frame_wait_cancel)(struct wfs_iface *cur_if);
	/**
	 * set_ap -- Set Beacon and Probe response for AP mode
	 * @params: AP parameters
	 */
	enum wfs_internal_err
		(*set_ap)(struct wfs_driver_ap_params *params);
	/**
	 * set_country -- Ask to set the regulatory domain to the specified
	 *                ISO/IEC 3166-1 alpha2 country code
	 * @cur_if: current interface
	 * @country_code: country code to switch to
	 */
	enum wfs_internal_err
		(*set_country)(struct wfs_iface *cur_if,
				const u8 *country_code);
	/**
	 * set_cqm -- Set connection quality monitor parameters
	 * @params: cqm parameters
	 */
	enum wfs_internal_err
		(*set_cqm)(struct wfs_driver_cqm_params *params);
	/**
	 * set_key -- Configure encryption key
	 * @params: key parameters
	 */
	enum wfs_internal_err
		(*set_key)(struct wfs_driver_key_params *params);
	/**
	 * set_mac_addr -- Set MAC address
	 * @cur_if: current interface
	 * @addr: MAC address
	 */
	enum wfs_internal_err
		(*set_mac_addr)(struct wfs_iface *cur_if, const u8 *addr);
	/**
	 * sta_add -- Add a station entry
	 * @params: station paameters
	 */
	enum wfs_internal_err
		(*sta_add)(struct wfs_driver_sta_add_params *params);
	/**
	 * sta_deauth -- Deauthenticate a station (AP only)
	 * @cur_if: current interface
	 * @addr: station address to be deauthenticated
	 * @reason_code: reason code in deauthentication frame
	 */
	enum wfs_internal_err
		(*sta_deauth)(struct wfs_iface *cur_if, const u8 *addr,
				u16 reason_code);
	/**
	 * sta_disassoc -- Disassociate a station (AP only)
	 * @cur_if: current interface
	 * @addr: station address to be disassociated
	 * @reason_code: reason code in disassociation frame
	 */
	enum wfs_internal_err
		(*sta_disassoc)(struct wfs_iface *cur_if, const u8 *addr,
				u16 reason_code);
	/**
	 * status -- Get current status information
	 * @cur_if: current interface
	 * @buf: buffer to fill
	 * @buf_len: length of buffer
	 * @filled_len: number of bytes filled
	 */
	enum wfs_internal_err
		(*status)(struct wfs_iface *cur_if, u8 *buf, u32 buf_len,
				u32 *filled_len);
	/**
	 * stop_ap -- Stop AP operation on the AP interface
	 * @cur_if: current interface
	 */
	enum wfs_internal_err
		(*stop_ap)(struct wfs_iface *cur_if);
	/**
	 * stop_sched_scan -- Request driver to stop scheduled scan
	 * @cur_if: current interface
	 */
	enum wfs_internal_err
		(*stop_sched_scan)(struct wfs_iface *cur_if);
};

/** Wrappers of driver ops */
static inline enum wfs_internal_err
wfs_driver_associate(struct wfs_iface *cur_if,
		struct wfs_driver_assoc_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->associate)
		return cur_if->driver_ops->associate(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_auth(struct wfs_iface *cur_if, struct wfs_driver_auth_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->auth)
		return cur_if->driver_ops->auth(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_cancel_remain_on_channel(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->cancel_remain_on_channel)
		return cur_if->driver_ops->cancel_remain_on_channel(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_deauth(struct wfs_iface *cur_if, const u8 *addr, u16 reason_code)
{
	if (cur_if->driver_ops && cur_if->driver_ops->deauth)
		return cur_if->driver_ops->deauth(cur_if, addr, reason_code);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_deinit(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->deinit)
		return cur_if->driver_ops->deinit(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_del_sta(struct wfs_iface *cur_if, const u8 *addr)
{
	if (cur_if->driver_ops && cur_if->driver_ops->del_sta)
		return cur_if->driver_ops->del_sta(cur_if, addr);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_get_bssid(struct wfs_iface *cur_if, u8 *bssid)
{
	if (cur_if->driver_ops && cur_if->driver_ops->get_bssid)
		return cur_if->driver_ops->get_bssid(cur_if, bssid);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_get_country(struct wfs_iface *cur_if, u8 *country_code)
{
	if (cur_if->driver_ops && cur_if->driver_ops->get_country)
		return cur_if->driver_ops->get_country(cur_if, country_code);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_get_hw_info(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->get_hw_info)
		return cur_if->driver_ops->get_hw_info(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_get_mac_addr(struct wfs_iface *cur_if, u8 *addr)
{
	if (cur_if->driver_ops && cur_if->driver_ops->get_mac_addr)
		return cur_if->driver_ops->get_mac_addr(cur_if, addr);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline struct wfs_driver_scan_results *
wfs_driver_get_scan_results(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->get_scan_results)
		return cur_if->driver_ops->get_scan_results(cur_if);
	return NULL;
}

static inline enum wfs_internal_err
wfs_driver_get_ssid(struct wfs_iface *cur_if, u8 *ssid, u32 *ssid_len)
{
	if (cur_if->driver_ops && cur_if->driver_ops->get_ssid)
		return cur_if->driver_ops->get_ssid(cur_if, ssid, ssid_len);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_if_add(struct wfs_iface *cur_if, struct wfs_driver_if_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->if_add)
		return cur_if->driver_ops->if_add(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_if_remove(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->if_remove)
		return cur_if->driver_ops->if_remove(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_init(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->init)
		return cur_if->driver_ops->init(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline int
wfs_driver_is_scan_ongoing(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->is_scan_ongoing)
		return cur_if->driver_ops->is_scan_ongoing(cur_if);
	return FALSE;
}

static inline enum wfs_internal_err
wfs_driver_probe_client(struct wfs_iface *cur_if, const u8 *addr, u8 is_qos)
{
	if (cur_if->driver_ops && cur_if->driver_ops->probe_client)
		return cur_if->driver_ops->probe_client(cur_if, addr, is_qos);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_remain_on_channel(struct wfs_iface *cur_if, u32 freq, u32 duration)
{
	if (cur_if->driver_ops && cur_if->driver_ops->remain_on_channel)
		return cur_if->driver_ops->remain_on_channel(cur_if, freq,
				duration);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_scan(struct wfs_iface *cur_if, struct wfs_driver_scan_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->scan)
		return cur_if->driver_ops->scan(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_sched_scan(struct wfs_iface *cur_if,
		struct wfs_driver_scan_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->sched_scan)
		return cur_if->driver_ops->sched_scan(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_send_frame(struct wfs_iface *cur_if,
		struct wfs_driver_frame_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->send_frame)
		return cur_if->driver_ops->send_frame(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_send_frame_wait_cancel(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->send_frame_wait_cancel)
		return cur_if->driver_ops->send_frame_wait_cancel(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_set_ap(struct wfs_iface *cur_if,
		struct wfs_driver_ap_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->set_ap)
		return cur_if->driver_ops->set_ap(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_set_country(struct wfs_iface *cur_if, const u8 *country_code)
{
	if (cur_if->driver_ops && cur_if->driver_ops->set_country)
		return cur_if->driver_ops->set_country(cur_if, country_code);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_set_cqm(struct wfs_iface *cur_if,
		struct wfs_driver_cqm_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->set_cqm)
		return cur_if->driver_ops->set_cqm(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_set_key(struct wfs_iface *cur_if,
		struct wfs_driver_key_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->set_key)
		return cur_if->driver_ops->set_key(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_set_mac_addr(struct wfs_iface *cur_if, const u8 *addr)
{
	if (cur_if->driver_ops && cur_if->driver_ops->set_mac_addr)
		return cur_if->driver_ops->set_mac_addr(cur_if, addr);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_sta_add(struct wfs_iface *cur_if,
		struct wfs_driver_sta_add_params *params)
{
	params->iface = cur_if;
	if (cur_if->driver_ops && cur_if->driver_ops->sta_add)
		return cur_if->driver_ops->sta_add(params);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_sta_deauth(struct wfs_iface *cur_if, const u8 *addr, u16 reason_code)
{
	if (cur_if->driver_ops && cur_if->driver_ops->sta_deauth)
		return cur_if->driver_ops->sta_deauth(cur_if, addr,
				reason_code);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_sta_disassoc(struct wfs_iface *cur_if, const u8 *addr,
		u16 reason_code)
{
	if (cur_if->driver_ops && cur_if->driver_ops->sta_disassoc)
		return cur_if->driver_ops->sta_disassoc(cur_if, addr,
				reason_code);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_status(struct wfs_iface *cur_if, u8 *buf, u32 buf_len,
		u32 *filled_len)
{
	if (cur_if->driver_ops && cur_if->driver_ops->status)
		return cur_if->driver_ops->status(cur_if, buf, buf_len,
				filled_len);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_stop_ap(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->stop_ap)
		return cur_if->driver_ops->stop_ap(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

static inline enum wfs_internal_err
wfs_driver_stop_sched_scan(struct wfs_iface *cur_if)
{
	if (cur_if->driver_ops && cur_if->driver_ops->stop_sched_scan)
		return cur_if->driver_ops->stop_sched_scan(cur_if);
	return WFS_INTERNAL_ERR_INVAL;
}

#endif /* DRIVER_H */
